/*
 * @Author: sunboy
 * @LastEditors: sunboy
 * @Date: 2025-07-28 12:12:57
 * @LastEditTime: 2025-10-13 19:11:35
 */
#include "uiohook.h"
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>

// 键盘事件数据结构体
typedef struct {
    uint8_t event_type;     // 事件类型
    uint16_t keycode;   // 键码
    uint16_t rawcode;   // 原始码
    uint16_t keychar;    // 字符
    uint16_t mask;
} keyboard_event_data_t;

// 内存管理模式枚举
typedef enum {
    MEMORY_STACK,       // 栈分配（默认，适用于同步C回调）
    MEMORY_HEAP         // 堆分配（适用于跨语言异步调用）
} memory_mode_t;

// 键盘事件回调函数类型定义（栈分配版本）
typedef void (*keyboard_callback_t)(const keyboard_event_data_t* event_data);

// 键盘事件回调函数类型定义（堆分配版本，需要手动释放）
typedef void (*keyboard_callback_heap_t)(keyboard_event_data_t* event_data);

// 内存释放函数类型
typedef void (*free_callback_t)(keyboard_event_data_t* event_data);

// 全局回调函数指针
static keyboard_callback_t keyboard_callback = NULL;
static keyboard_callback_heap_t keyboard_callback_heap = NULL;
static memory_mode_t memory_mode = MEMORY_STACK;


bool logger_proc(unsigned int level, const char *format, ...) {
    bool status = false;
    
    va_list args;
    switch (level) {
        case LOG_LEVEL_INFO:
            va_start(args, format);
            status = vfprintf(stdout, format, args) >= 0;
            va_end(args);
            break;

        case LOG_LEVEL_WARN:
        case LOG_LEVEL_ERROR:
            va_start(args, format);
            status = vfprintf(stderr, format, args) >= 0;
            va_end(args);
            break;
    }
    
    return status;
}

// 注册键盘事件回调函数（栈分配模式）
void set_keyboard_callback(keyboard_callback_t callback) {
    keyboard_callback = callback;
    keyboard_callback_heap = NULL;
    memory_mode = MEMORY_STACK;
}

// 注册键盘事件回调函数（堆分配模式，用于跨语言互操作）
void set_keyboard_callback_heap(keyboard_callback_heap_t callback) {
    keyboard_callback_heap = callback;
    keyboard_callback = NULL;
    memory_mode = MEMORY_HEAP;
}

// 释放堆分配的事件数据
void free_keyboard_event_data(keyboard_event_data_t* event_data) {
    if (event_data) {
        free(event_data);
    }
}

// 辅助函数：触发键盘事件回调
static void trigger_keyboard_callback(uiohook_event* event) {
    if (keyboard_callback || keyboard_callback_heap) {
        if (memory_mode == MEMORY_STACK && keyboard_callback) {
            // 栈分配模式 - 适用于同步C回调
            keyboard_event_data_t event_data = {
                .event_type = event->type,
                .keycode = event->data.keyboard.keycode,
                .rawcode = event->data.keyboard.rawcode,
                .keychar = (uint16_t)event->data.keyboard.keychar,
                .mask = event->mask
            };
            keyboard_callback(&event_data);
        } else if (memory_mode == MEMORY_HEAP && keyboard_callback_heap) {
            // 堆分配模式 - 适用于跨语言异步调用
            keyboard_event_data_t* event_data = malloc(sizeof(keyboard_event_data_t));
            if (event_data) {
                event_data->event_type = event->type;
                event_data->keycode = event->data.keyboard.keycode;
                event_data->rawcode = event->data.keyboard.rawcode;
                event_data->keychar = (uint16_t)event->data.keyboard.keychar;
                event_data->mask = event->mask;
                keyboard_callback_heap(event_data);
                // 注意：调用者负责释放内存
            }
        }
    }
}

void dispatch_proc(uiohook_event * const event) {
    //TODO: remove
    // char buffer[256] = { 0 };
    // size_t length = 0;
    
    switch (event->type) {
        case EVENT_KEY_PRESSED:
            // If the escape key is pressed, naturally terminate the program.
            if (event->data.keyboard.keycode == VC_ESCAPE) {
                int status = hook_stop();
                switch (status) {
                    case UIOHOOK_SUCCESS:
                        // Everything is ok.
                        break;

                    // System level errors.
                    case UIOHOOK_ERROR_OUT_OF_MEMORY:
                        logger_proc(LOG_LEVEL_ERROR, "Failed to allocate memory. (%#X)", status);
                        break;
            
                    case UIOHOOK_ERROR_X_RECORD_GET_CONTEXT:
                        // NOTE This is the only platform specific error that occurs on hook_stop().
                        logger_proc(LOG_LEVEL_ERROR, "Failed to get XRecord context. (%#X)", status);
                        break;

                    // Default error.
                    case UIOHOOK_FAILURE:
                    default:
                        logger_proc(LOG_LEVEL_ERROR, "An unknown hook error occurred. (%#X)", status);
                        break;
                }
            }
            printf("EVENT_KEY_PRESSED\n");
            //调用键盘事件回调函数
            trigger_keyboard_callback(event);
            
            // length = snprintf(buffer, sizeof(buffer), 
            //     "KEY_PRESSED: keycode=%u,rawcode=0x%X,keychar=%lc",
            //     event->data.keyboard.keycode, event->data.keyboard.rawcode, (uint16_t)event->data.keyboard.keychar);
            break;
            
        case EVENT_KEY_RELEASED:
           break;
        case EVENT_KEY_TYPED:
            printf("EVENT_KEY_TYPED\n");

            // 调用键盘事件回调函数
            trigger_keyboard_callback(event);
            
            // length = snprintf(buffer, sizeof(buffer), 
            //     "KEY_TYPED: keycode=%u,rawcode=0x%X, keychar=%lc",
            //     event->data.keyboard.keycode, event->data.keyboard.rawcode, (uint16_t)event->data.keyboard.keychar);
            break;

        case EVENT_MOUSE_PRESSED:
        case EVENT_MOUSE_RELEASED:
        case EVENT_MOUSE_CLICKED:
        case EVENT_MOUSE_MOVED:
        case EVENT_MOUSE_DRAGGED:
            // 如果不想输出鼠标事件，直接返回
            return;

        case EVENT_MOUSE_WHEEL:
            // 如果不想输出鼠标滚轮事件，直接返回
            return;

        default:
            return;
    }

    // 只有处理了的事件才会输出
    // if (length > 0) {
    //     fprintf(stdout, "%s\n", buffer);
    // }
}

void wrapper_hook_dispatch_proc() {
  hook_set_dispatch_proc(&dispatch_proc);
}